package com.wdl.datarest.implementation;

import org.apache.log4j.Logger;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Multi thread simulator for generating data.
 */
class DevSimMultiThread extends Thread {
/*
	//Don't use logger since it requires additional jar
	//private static final Logger log = Logger.getLogger("DevSimMultiThread");
	
	private String hostName;
	private int port;
    DatagramSocket socketClient;
    int indexofRoute;
	String dtuId;
	    
	DevSimMultiThread(int route, String threadName, String serverIP, int serverPort){
		indexofRoute = route;
		dtuId = threadName;
	    this.hostName = serverIP;
	    this.port = serverPort;
	}

    public String sendDeviceData(String Device) throws UnknownHostException, IOException{
		//Get a datagram socket
        socketClient = new DatagramSocket();

        //Send data
        byte[] bufwocrc = DataTransformUtil.hexStringToBytes(Device);
        byte[] buf4CRC = new byte[bufwocrc.length-4];
        byte[] buf= new byte[bufwocrc.length+2];
		for (int i= 0; i< buf4CRC.length;i++){
			buf4CRC[i]=bufwocrc[i+4];
		}

		// CRC16 (2 bytes)
		short crcInt = DataTransformUtil.getCrc16(buf4CRC,buf4CRC.length);
		byte[] crc = DataTransformUtil.short2bytes(crcInt);
		for (int i =0; i< bufwocrc.length; i++){
			buf[i] = bufwocrc[i];
		}
		buf[buf.length-2] = crc[0];
		buf[buf.length-1] = crc[1];

        
//		buf = Device.getBytes();
		System.out.println("************************************************");
		System.out.println("Data to be sent:" + buf.toString());
		System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++");
		
        InetAddress address = InetAddress.getByName(hostName);
        DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port);
        socketClient.send(packet);
    
        //Get response
        packet = new DatagramPacket(buf, buf.length);
        socketClient.receive(packet);

	    //Show response
        String received = new String(packet.getData(), 0, packet.getLength());
        System.out.println("Response from server: " + received);
    
        socketClient.close();
        return received;
    }
	
	public void run(){
		System.out.println("Thread-" + dtuId);
		
        int positionDataIndicator = 0;
		byte[] buf = new byte[500];
    	String devData;
        String respone;
		int dtuFrameNumber = 0;
        
        Random delayRandom = new Random();
        int delayBeforeStart = delayRandom.nextInt(300);
        try {
        	Thread.sleep(delayBeforeStart * 1000);
        } catch (InterruptedException ie){
        	ie.printStackTrace();
        }

		while (true){
	        Random r = new Random();

        	String dTUIdStr = dtuId;
        	float latitude;
        	float longitude;
        	if (indexofRoute < 13 ) {
        		int indexOfPosition = r.nextInt(lat[indexofRoute].length);
        		latitude = lat[indexofRoute][indexOfPosition];
        		longitude = lon[indexofRoute][indexOfPosition];
        	} else {
        		latitude = 36.1372f + r.nextFloat() * (36.3709f-36.1372f);
        		longitude = 120.3813f + r.nextFloat() * (120.6526f-120.3813f);
        	}
			//Device frameNumber (2 bytes) 
			dtuFrameNumber = dtuFrameNumber +1;
			byte[] buf2 = new byte[2];
			buf2[0] = (byte)((dtuFrameNumber - dtuFrameNumber%256)/256);
			buf2[1] = (byte)(dtuFrameNumber%256);
			String dtuFrameNumberString = DataTransformUtil.Bytes2HexString(buf2);
			if (dtuFrameNumber == 65536){
				dtuFrameNumber =0;
			}

			//Device current time (6 bytes)
			DateFormat format2 = new java.text.SimpleDateFormat("yyMMddHHmmss");
			String dataTime = format2.format(new Date());

        	System.out.println(DataTransformUtil.Bytes2HexString(dTUIdStr.getBytes())+"("+dTUIdStr+")");
        	//construct Key type data;
        	devData = DataTransformUtil.Bytes2HexString("NWX".getBytes())
        			+ "01" 											
        			+"00b7" 										
        			+dtuFrameNumberString							
        			+DataTransformUtil.Bytes2HexString(dTUIdStr.getBytes())
        			+"0001"										
        			+"11"											
        			+DataTransformUtil.Bytes2HexString(dataTime.getBytes())		
        			+"01"									
        			+"00"											

        			;
//        	devData = Bytes2HexString(buf);
        	System.out.println("SIM: Sending 1st set of data...");
        	try {
				respone = sendTpmsData(devData);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

            //construct Float type data;
        	devData = DataTransformUtil.Bytes2HexString("NWX".getBytes()) 	//帧头
        			+ "02" 											//帧类型
        			+"00fe" 										//长度
        			+dtuFrameNumberString							//帧序号 2 bytes
        			+DataTransformUtil.Bytes2HexString(dTUIdStr.getBytes())			//DTU ID
        			+"0001"											//地址（暂定写0x01）2 bytes
        			+"12"											//包类型（0x11,高位的1表示版本号）
        			+DataTransformUtil.Bytes2HexString(dataTime.getBytes())			//采集时间（按照3.3节规定）12 bytes
        			+"01"											//起始通道号 此处写0x1

        			;
        	
        	System.out.println("SIM: Sending 2nd set of data...");
            try {
				respone = sendTpmsData(devData);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        	//construct String type data;
        	String headData = DataTransformUtil.Bytes2HexString("NWX".getBytes()) 	//帧头
        			+ "03" 											//帧类型
        			+"0100" 										//长度
        			+dtuFrameNumberString							//帧序号 2 bytes
        			+DataTransformUtil.Bytes2HexString(dTUIdStr.getBytes())			//DTU ID
        			+"0001"											//地址（暂定写0x01）2 bytes
					+"13"											//包类型（0x11,高位的1表示版本号）
					+DataTransformUtil.Bytes2HexString(dataTime.getBytes())			//采集时间（按照3.3节规定）12 bytes
					+"01"											//起始通道号 此处写0x1
					;

        	String stringType="1,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99," + String.valueOf(latitude) + ",0," + String.valueOf(longitude) + ",0,83A22D,83A18E,839F45,838D4B,839457,8394C0,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,-99.99,";
        	System.arraycopy(DataTransformUtil.hexStringToBytes(headData), 0, buf, 0, DataTransformUtil.hexStringToBytes(headData).length);
        	System.arraycopy(stringType.getBytes(), 0, buf, DataTransformUtil.hexStringToBytes(headData).length, stringType.getBytes().length);

        	devData = DataTransformUtil.Bytes2HexString(buf);
        	System.out.println("SIM: Sending 3rd set of data...");
            try {
				respone = sendTpmsData(devData);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            
	        //Send data to server every 5mins. If this need be changeable support a parameter on command line
	        try {
	        	Thread.sleep(1000 * 60 * 1);
	        } catch (InterruptedException ie){
	        	ie.printStackTrace();
	        }
		}
	}
}

public class TpmsDtuSim {
	private static String[] bus762 = {"KT003", "KT004"};

	private static String[][] busGrp5 = 
		{bus762, bus763, bus768, bus769, bus761, bus103, bus111, bus117, bus120, bus372, bus374, bus502, bus631};

    public static void main(String[] args){
    	String usage = "\n" +
    				   "On the server in the folder apache-tomcat-8.0.14\\webapps\\BusMonitor\\WEB-INF\\classes execute below command" +
    				   "\njava com.wdl.busmonitor.implementation.TpmsDtuSim <BusMonitorServerIP> <BusMonitorServerPort> <NumOfDtu>" +
    				   "\n BusMonitorServerIP - IP address of the Bus Monitor System server" + 
    				   "\n BusMonitorServerPort - Port that the Bus Monitor System is listening to" +
    				   "\n NumOfDtu - Number of DTUs for this simulator to simulate. 1 =< NumOfDtu =< 6000" +
    				   "\n" +
    				   "\n Example: java TpmsDtuSim 114.215.148.191 10086 1500" +
    				   "\n";
    	
    	// Don't want to introduce Apache cli jar, so handle options by self
    	if (args.length != 3) {
    		System.out.println(usage);
    		System.exit(1);
    	} 
    	
    	String serverIP = args[0];
    	String serverPort = args[1];
    	String dtuNum = args[2];
    	int iServerPort = 10086;
    	int iDtuNum = 100;
    	
    	Pattern pattern = Pattern.compile("(2[5][0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})");
    	Matcher matcher = pattern.matcher(serverIP);
    	if(matcher.matches() == false){
    		System.out.println("Wrong format of BusMonitor Server IP address");
    		System.out.println(usage);
    		System.exit(2);
    	}
    	
    	try {
    		iServerPort = Integer.parseInt(serverPort);
    	} catch (NumberFormatException nfe) {
    		System.out.println("Wrong format of BusMonitor Server port");
    		System.out.println(usage);
    		System.exit(3);
    	}
    	
    	try {
    		iDtuNum = Integer.parseInt(dtuNum);
    		if ( iDtuNum < 1 || iDtuNum > 6000){
        		System.out.println("NumOfDtu should be a value between 1 and 6000 (including 1 and 6000).");
        		System.out.println(usage);
        		System.exit(3);
    		}
    	} catch (NumberFormatException nfe) {
    		System.out.println("Wrong format of number of DTUs to simulate");
    		System.out.println(usage);
    		System.exit(3);
    	}
    
        //DeviceSim client = new DeviceSim ("114.215.148.191",10086);
    	
        BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>();    
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(iDtuNum, Integer.MAX_VALUE, 1, TimeUnit.DAYS, taskQueue);    
    	for (int i=0; i< busGrp5.length; i++)
        for (int j=0; j < busGrp5[i].length; j++) {
        	String strhstDev = busGrp5[i][j];
        	String tmpDtuName = "00000" + strhstDev.substring(2);
        
        	threadPool.execute(new TpmsDtuThread(i, tmpDtuName, serverIP, iServerPort));
        	try {
        		Thread.sleep(10);
        	} catch (InterruptedException ie) {
        		ie.printStackTrace();
        	}
        }
        
        threadPool.shutdown();
    }
*/
}